package com.hanser.hancoder.service.Impl.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.hanser.hancoder.exception.BusinessException;
import com.hanser.hancoder.exception.ErrorCode;
import com.hanser.hancoder.exception.ThrowUtils;
import com.hanser.hancoder.service.Impl.service.ProjectDownloadService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Locale;
import java.util.Set;

@Slf4j
@Service
public class ProjectDownloadServiceImpl implements ProjectDownloadService {
    /**
     * 需要过滤的文件和目录名称
     */
    private static final Set<String> IGNORED_NAMES = Set.of(
            "node_modules",
            ".git",
            "dist",
            "build",
            ".DS_Store",
            ".env",
            "target",
            ".mvn",
            ".idea",
            ".vscode"
    );

    /**
     * 需要过滤的文件扩展名
     */
    private static final Set<String> IGNORED_EXTENSIONS = Set.of(
            ".log",
            ".tmp",
            ".cache"
    );

    @Override
    public void downloadProjectAsZip(String projectPath, String downloadFileName, HttpServletResponse response) {
        // 基础校验
        ThrowUtils.throwIf(StrUtil.isBlank(projectPath), ErrorCode.PARAMS_ERROR, "项目路径不能为空！");
        ThrowUtils.throwIf(StrUtil.isBlank(downloadFileName), ErrorCode.PARAMS_ERROR, "下载文件名不能为空！");
        File projectDir = new File(projectPath);
        ThrowUtils.throwIf(!projectDir.exists(), ErrorCode.PARAMS_ERROR, "项目路径不存在！");
        ThrowUtils.throwIf(!projectDir.isDirectory(), ErrorCode.PARAMS_ERROR, "项目路径不是目录！");
        log.info("开始打包项目:{}->{}", projectPath, downloadFileName);
        // 设置HTTP响应头
        response.setStatus(HttpServletResponse.SC_OK);
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s.zip\"", downloadFileName));
        // 打包
        FileFilter filter = file -> isPathAllowed(projectDir.toPath(), file.toPath());
        try {
            ZipUtil.zip(response.getOutputStream(), StandardCharsets.UTF_8, false, filter, projectDir);
            log.info("打包项目成功：{}->{}", projectPath, downloadFileName);
        } catch (IOException e) {
            log.error("打包项目时出错：{}->{}", projectPath, downloadFileName, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "打包项目时出错");
        }
    }

    /**
     * 判断路径是否允许下载
     *
     * @param projectRoot 项目根目录
     * @param fullPath    完整路径
     * @return 是否允许下载
     */
    private boolean isPathAllowed(Path projectRoot, Path fullPath) {
        Path relativePath = projectRoot.relativize(fullPath);
        // 检查路径中的没一部分
        for (Path path : relativePath) {
            String partName = path.toString();
            // 检查是否在忽略列表中
            if (IGNORED_NAMES.contains(partName)) {
                return false;
            }
            // 检查扩展名
            if (IGNORED_EXTENSIONS.stream().anyMatch(ext -> partName.toLowerCase(Locale.ROOT).endsWith(ext))) {
                return false;
            }
        }
        return true;
    }
}
